package com.study.refor2020;

import com.study.util.FileUtil;
import com.study.util.StringUtil;
import com.study.refor2020.dto.ClassField;
import com.study.refor2020.dto.ClassInfo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @version V1.0
 * @title: CoverPbService
 * @description: ${DESCRIPTION}
 * @author: wanghuilong
 * @date: 2020-08-28 14:06
 * @copyright: http://fingo.com.my/
 */
public class CoverPbService {

    //基本目录
    private static final String DIR = "/Users/fingo/IdeaProjects/user-center/user-iface/src/main/java/";

    //PB文件
    private static final String PB_FILE = "/Users/fingo/IdeaProjects/littlec-api/proto/core/member.proto";

    //Enum PB文件
    private static final String ENUM_PB_FILE = "/Users/fingo/IdeaProjects/littlec-api/proto/common/enum.proto";

    //API包
    private static final String API_PACKAGE = "api.core";

    //Enum包
    private static final String ENUM_PACKAGE = "consts";

    //匹配Message
    private static final String MESSAGE_CLASS_PATTERN = ".*message [a-zA-Z]+[ ]*\\{\\n(.*\\n)*?\\}";

    private static final String SUB_MESSAGE_CLASS_PATTERN = ".*message [a-zA-Z]+[ ]*\\{\\n(.*\\n)*?[ ]*\\}";

    //匹配Service
    private static final String SERVICE_CLASS_PATTERN = ".*service [a-zA-Z]+[ ]*\\{\\n(.*\\n)*?\\}";

    //匹配Enum
    private static final String Enum_CLASS_PATTERN = ".*enum [a-zA-Z]+[ ]*\\{\\n(.*\\n)*?[ ]*\\}";

    private static final List<String> serviceNameList = Arrays.asList(
            //"UserLoginService","UserQuestionService","UserAddressService","UserService"
            "AuthCodeService", "UserDeviceService"
    );

    //匹配{}里面的内容
    private static final String CONTENT_PATTERN = "\\{\\n(.*\\n)*?[ ]*\\}";

    private static final String basePackage = "com.fingo.user";

    //enum创建 RegisterChannelEnum/OrderCommissionTypeEnum
    private static final List<String> enumNameList = new ArrayList<>();

    public static void main(String[] args) {
        //模块名称
        String[] split = basePackage.split("\\.");
        String moduleName = split[split.length - 1];

        //读取文件
        String fileStr = FileUtil.read(PB_FILE);
        //获取所有Message
        List<String> messageList = matcher(fileStr, MESSAGE_CLASS_PATTERN);


        List<ClassInfo> classInfoList = new ArrayList<>();
        for (int i = 0; i < messageList.size(); i++) {
            ClassInfo classInfo = coverClassInfo(messageList.get(i), classInfoList);
            classInfoList.add(classInfo);

        }
        //生成Req/Resp/DTO Class File
        for (int i = 0; i < classInfoList.size(); i++) {
            createClassInfo(classInfoList.get(i));
        }

        String enumFileStr = FileUtil.read(ENUM_PB_FILE);
        enumFileStr = enumFileStr.replaceAll("\t", "");
        //获取所有EnumMessage
        List<String> enumMessageList = matcher(enumFileStr, MESSAGE_CLASS_PATTERN);
        for (int i = 0; i < enumMessageList.size(); i++) {
            String enumMessage = enumMessageList.get(i);
            List<String> enums = matcher(enumMessage, Enum_CLASS_PATTERN);
            for (int j = 0; j < enums.size(); j++) {
                String enumClassStr = enums.get(j);
                String firstLine = enumClassStr.split("\n")[0].trim();
                String enumName = firstLine.replaceAll("\\{", "")
                        .replaceAll("enum", "").trim();
                if (enumNameList.contains(enumName)) {
                    List<String> content = matcher(enumClassStr, CONTENT_PATTERN);
                    String innerContent = content.get(0).replaceAll("\\{", "")
                            .replaceAll("\\}", "");
                    String[] splitContents = innerContent.split("\n");
                    String enumPackage = basePackage + "." + ENUM_PACKAGE;
                    String enumPath = DIR + enumPackage.replaceAll("\\.", "/")
                            + "/" + enumName + ".java";

                    List<String> enumList = new ArrayList<>();
                    enumList.add("package " + enumPackage + ";\n");
                    enumList.add("public enum " + enumName + " {\n");
                    for (int k = 0; k < splitContents.length; k++) {
                        String line = splitContents[k];
                        if (line.indexOf("NULL") == -1) {
                            line = line.replaceAll("=", "(").replaceAll(";", "),");
                            enumList.add(line);
                        }
                    }
                    enumList.add(";");
                    enumList.add("\tpublic int value;\n");
                    enumList.add(enumName + " (int value) {\n");
                    enumList.add("\t this.value = value;\n");
                    enumList.add("\t}\n");
                    enumList.add("}");
                    FileUtil.writeToFileByLine(enumList, enumPath);
                }
            }
        }


        Map<String, String> messageCollect = classInfoList.stream()
                .collect(Collectors.toMap(ClassInfo::getClassName, ClassInfo::getPackageStr, (k1, k2) -> k1));
        //获取所有Service
        List<String> serviceList = matcher(fileStr, SERVICE_CLASS_PATTERN);
        for (int i = 0; i < serviceList.size(); i++) {
            String serviceStr = serviceList.get(i);
            String firstLine = serviceStr.split("\n")[0];
            String serviceName = firstLine.replace("service", "").replace("{", "").trim();
            if (serviceNameList.size() != 0 && serviceNameList.contains(serviceName)) {
                List<String> content = matcher(serviceStr, CONTENT_PATTERN);
                String str = content.get(0).replaceAll("\\{", "").replaceAll("\\}", "");
                String[] splitMethods = str.split(";");

                //生成Service Interface File
                String servicePackage = basePackage + "." + API_PACKAGE;
                String servicePath = DIR + servicePackage.replaceAll("\\.", "/") + "/" + serviceName + ".java";
                List<String> strList = new ArrayList<>();
                strList.add("package " + servicePackage + ";");
                strList.add("\n");
                strList.add("import com.fingo.littlec.ApiResult;\n");
                strList.add("import com.fingo." + moduleName + ".request.*;\n");
                strList.add("import com.fingo." + moduleName + ".response.*;\n");
                strList.add("\n");
                strList.add("public interface " + serviceName + " {\n");

                for (int j = 0; j < splitMethods.length; j++) {
                    String splitMethod = splitMethods[j];
                    if (splitMethod.indexOf("//") > -1) {
                        splitMethod = splitMethod.substring(splitMethod.indexOf("//"));
                    }
                    String[] strs = splitMethod.split("\n");
                    if (strs.length == 0) {
                        continue;
                    }
                    String methodContent = null;
                    String method = null;
                    if (strs.length > 1) {
                        methodContent = strs[0].replaceAll("//", "");
                        method = strs[1];
                    } else {
                        method = strs[0];
                    }
                    method = method.replaceAll("rpc", "")
                            .replaceAll(";", "")
                            .replaceAll("returns", "")
                            .replaceAll("\\(", " ")
                            .replaceAll("\\)", " ");
                    if (methodContent != null) {
                        strList.add("\t/**\n");
                        strList.add("\t * " + methodContent + "\n");
                        strList.add("\t *\n");
                        strList.add("\t * @param req\n");
                        strList.add("\t * @return\n");
                        strList.add("\t*/\n");
                    }
                    String[] methodStr = method.trim().split(" ");
                    List<String> methodStrList = new ArrayList<>();
                    for (int k = 0; k < methodStr.length; k++) {
                        if (StringUtil.isNotBlank(methodStr[k])) {
                            methodStrList.add(methodStr[k]);
                        }
                    }
                    String methodName = methodStrList.get(0);
                    methodName = methodName.substring(0, 1).toLowerCase() + methodName.substring(1);
                    String reqName = methodStrList.get(1);
                    String respName = methodStrList.get(2);
                    strList.add("\tApiResult<" + respName + "> " + methodName + "(" + reqName + " req);\n");
                }
                strList.add("}");
                FileUtil.writeToFileByLine(strList, servicePath);
            }
        }
    }

    private static void createClassInfo(ClassInfo classInfo) {
        String path = DIR + classInfo.getPackageStr().replaceAll("\\.", "/")
                + "/" + classInfo.getClassName() + ".java";

        List<String> list = new ArrayList<>();
        list.add("package " + classInfo.getPackageStr() + ";");
        list.add("\n");
        List<String> importList = classInfo.getImportList();
        for (int i = 0; null != importList && i < importList.size(); i++) {
            list.add("import " + importList.get(i) + ";\n");
        }


        list.add("import lombok.AllArgsConstructor;\n");
        list.add("import lombok.Builder;\n");
        list.add("import lombok.Data;\n");
        list.add("import lombok.NoArgsConstructor;\n");
        list.add("\n");
        list.add("@Data\n");
        list.add("@Builder\n");
        list.add("@NoArgsConstructor\n");
        list.add("@AllArgsConstructor\n");
        list.add("public class " + classInfo.getClassName() + " {\n");
        List<ClassField> fields = classInfo.getFields();
        if (fields != null && fields.size() > 0) {
            for (int i = 0; i < fields.size(); i++) {
                ClassField classField = fields.get(i);
                list.add("\n");
                if (null != classField.getContent()) {
                    list.add("\t/**\n");
                    list.add("\t *" + classField.getContent() + "\n");
                    list.add("\t*/\n");
                }
                list.add("\tprivate " + classField.getType() + " " + coverClassNameXxx(classField.getName()) + ";");
                list.add("\n");
            }
        }
        list.add("}");
        FileUtil.writeToFileByLine(list, path);
    }

    public static String coverClassNameXxx(String className) {
        if (className.indexOf("_") > -1) {
            String[] strings = className.split("_");
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < strings.length; i++) {
                if (i > 0) {
                    stringBuilder.append(strings[i].substring(0, 1).toUpperCase())
                            .append(strings[i].substring(1));
                } else {
                    stringBuilder.append(strings[i]);
                }
            }
            return stringBuilder.toString();
        }

        return className;
    }

    private static ClassInfo coverClassInfo(String str, List<ClassInfo> classInfoList) {
        String[] split = str.split("\n");
        List<String> strList = new ArrayList<>();
        for (int i = 0; i < split.length; i++) {
            strList.add(split[i]);
        }
        ClassInfo classInfo = new ClassInfo();
        String firstLine = strList.get(0);
        String messageName = firstLine.replace("message", "").replace("{", "").trim();
        classInfo.setClassName(messageName);

        //导入包
        List<String> importList = new ArrayList<>();

        strList.remove(0);
        String contentSourceStr = StringUtil.join(strList, "\n").replaceAll("\t", "");
        //是否有包含的message
        List<String> subMessage = matcher(contentSourceStr, SUB_MESSAGE_CLASS_PATTERN);

        if (subMessage.size() > 0) {
            for (int i = 0; i < subMessage.size(); i++) {
                String subMessageStr = subMessage.get(i);
                ClassInfo innerClassInfo = coverClassInfo(subMessageStr, classInfoList);
                classInfoList.add(innerClassInfo);
                String[] subSplit = subMessageStr.split("\n");
                //删除包含的message 内容
                List<String> tmpList = new ArrayList<>();
                for (int k = 0; k < strList.size(); k++) {
                    String tmpStr = strList.get(k);
                    boolean key = true;
                    in:
                    for (int j = 0; j < subSplit.length; j++) {
                        String tmpStr2 = strList.get(j);
                        if (tmpStr.equals(tmpStr2)) {
                            key = false;
                            break in;
                        }
                    }
                    if (key) {
                        tmpList.add(tmpStr);
                    }
                }
                strList = tmpList;
            }
        }

        List<ClassField> classFieldList = new ArrayList<>();
        String lastContent = null;
        for (int i = 0; i < strList.size(); i++) {
            String s = strList.get(i).replaceAll("\t", "").replaceAll("\\{", "")
                    .replaceAll("\\}", "").trim();
            if (!StringUtil.isNotBlank(s)) {
                continue;
            }
            //判断是否为注释
            if (s.startsWith("//")) {
                lastContent = s.replaceAll("//", "");
                continue;
            }
            ClassField classField = coverClassField(s, lastContent, importList, classInfoList);
            classFieldList.add(classField);
            lastContent = null;
        }
        classInfo.setFields(classFieldList);
        if (classInfo.getClassName().indexOf("Req") > -1) {
            classInfo.setPackageStr(basePackage + ".request");
        }
        if (classInfo.getClassName().indexOf("Resp") > -1) {
            classInfo.setPackageStr(basePackage + ".response");
        }
        if (classInfo.getPackageStr() == null) {
            classInfo.setPackageStr(basePackage + ".dto");
        }
        classInfo.setImportList(importList);

        return classInfo;
    }

    private static ClassField coverClassField(String s, String lastContent, List<String> importList
            , List<ClassInfo> classInfoList) {
        String[] lineArr = s.split(";");
        String str = lineArr[0].trim();
        String header = str.split("=")[0].trim();
        String content = lastContent;
        String[] s1 = header.replaceAll(", ", ",").split(" ");
        ClassField classField = new ClassField();
        if (s1.length == 2) {
            String type = s1[0].trim();
            String name = s1[1].trim();
            classField.setType(type);
            classField.setName(name);
        } else if (s1.length == 3) {
            String type = "List<" + s1[1].trim() + ">";
            String name = s1[2].trim();
            classField.setType(type);
            classField.setName(name);
        }
        classField.setType(coverFieldType(classField.getType(), importList, classInfoList));
        if (s.indexOf("//") > -1) {
            String contentStr = s.split("//")[1];
            content = lastContent == null ? contentStr : lastContent + "," + contentStr;
        }
        classField.setContent(content);
        return classField;
    }

    private static String coverFieldType(String type, List<String> importList, List<ClassInfo> classInfoList) {
        Map<String, String> collect = classInfoList.stream()
                .collect(Collectors.toMap(ClassInfo::getClassName, ClassInfo::getPackageStr, (k1, k2) -> k1));
        if (type.indexOf("map") > -1) {
            String tmp = type.replaceAll("map<", "").replaceAll(">", "");
            String[] tmpSplits = tmp.split(",");
            String key = tmpSplits[0];
            String value = tmpSplits[1];
            if (!importList.contains("java.util.Map")) {
                importList.add("java.util.Map");
            }
            key = coverFieldType(key, importList, classInfoList);
            value = coverFieldType(value, importList, classInfoList);
            return "Map<" + key + "," + value + ">";
        } else if (type.indexOf("common.base.Pagination") > -1) {
            if (!importList.contains("com.fingo.user.common.Pagination")) {
                importList.add("com.fingo.user.common.Pagination");
            }
            return "Pagination";
        } else if (type.indexOf("List") > -1) {
            String tmpType = type.replaceAll("List", "").replaceAll("<", "")
                    .replaceAll(">", "");
            if (!importList.contains("java.util.List")) {
                importList.add("java.util.List");
            }
            String realType = coverFieldType(tmpType, importList, classInfoList);
            return "List<" + realType + ">";
        } else if (type.indexOf("common.base.ErrorMessage") > -1) {
            if (!importList.contains("com.fingo.littlec.proto.common.Base")) {
                importList.add("com.fingo.littlec.proto.common.Base");
            }
            return "Base.ErrorMessage";
        } else if (type.indexOf("enum") > -1) {
            String enumName = type.substring(type.lastIndexOf(".") + 1);
            enumNameList.add(enumName);
            String packageStr = basePackage + "." + ENUM_PACKAGE + "." + enumName;
            if (!importList.contains(packageStr)) {
                importList.add(packageStr);
            }
            return enumName;
        } else if (null != collect.get(type)) {
            String packageStr = collect.get(type);
            if (!importList.contains(packageStr)) {
                importList.add(packageStr + "." + type);
            }
            return type;
        }

        return coverBaseFieldType(type);
    }

    private static String coverBaseFieldType(String type) {
        switch (type) {
            case "bool":
                return "Boolean";
            case "string":
                return "String";
            case "int32":
                return "Integer";
            case "int64":
                return "Long";
            default:
                return null;
        }
    }


    public static List<String> matcher(String str, String pattern) {
        List<String> list = new ArrayList<>();
        if (!StringUtil.isNotBlank(str)) {
            return list;
        }

        // 创建 Pattern 对象
        Pattern r = Pattern.compile(pattern);

        // 现在创建 matcher 对象
        Matcher m = r.matcher(str);
        while (m.find()) {
            list.add(m.group());
        }

        return list;
    }


}
